package cn.mabach.dianping.service.impl;

import cn.mabach.dianping.dao.ShopDao;
import cn.mabach.dianping.dto.ShopDto;
import cn.mabach.dianping.entity.ShopEntity;
import cn.mabach.dianping.mongoDb.ShopMongo;
import cn.mabach.dianping.propertie.CategoryProperties;
import cn.mabach.dianping.propertie.ListProperties;
import cn.mabach.dianping.service.ShopService;
import cn.mabach.entity.CategorySetEntity;
import cn.mabach.result.PageResult;
import cn.mabach.result.RS;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;


@RestController
@Slf4j
public class ShopsServiceImpl extends ServiceImpl<ShopDao, ShopEntity> implements ShopService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;
    @Autowired
    private CategoryProperties categoryProperties;

    private static final double BOOST =0.001; //关键词权重

    private static final double DISTANCE_WEIGHT=10; //高斯距离评分权重

    private static final double REMARK_SCORE_WEIGHT=0.002; //remark_score评分权重

    private static final double SELLER_REMARK_SCORE_WEIGHT=0; //seller_remark_score评分权重

    private static final double CATEGORY_ID_WEIGHT=6; //类目排序权重
    private static final double PRICE_WEIGHT=8; //价格权重

    private static final String SCORE_MODE="sum" ;//functions中各项评分相加

    private static final String BOOST_MODE="sum" ;//function_score和functions分数相加




    @Autowired
    ShopMongo shopMongo;
    @Autowired
    private RedisTemplate redisTemplate;





    @Override
    public String printlog2() throws InterruptedException {
        List<ShopEntity> list = this.list(null);
        for (ShopEntity shopEntity : list) {

            shopEntity.setLogo("http://img.mabach.cn/lewa.jpg");
            this.updateByIdE(shopEntity);
        }

        return "发送成功";
    }

    @Override
    public PageResult queryPage(@RequestParam(value = "keyword", required = false) String keyword,
                                @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
                                @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {

        IPage<ShopEntity> page = this.page(
                new Page<ShopEntity>(pageNum,pageSize),
                new QueryWrapper<ShopEntity>().like(!StringUtils.isEmpty(keyword),"name",keyword)
        );

        return new PageResult(page);
    }

    @Override
    public ShopEntity getByIdE(Integer id) {
        return this.getById(id);
    }

    @Override
    public RS saveE(ShopEntity entity) {
        boolean b = this.save(entity);
        if (!b){
            return RS.error();
        }
        return RS.ok();

    }

    @Override
    public RS updateByIdE(ShopEntity entity) {
        boolean b = this.updateById(entity);
        if (!b){
            return RS.error();
        }
        return RS.ok();
    }

    @Override
    public RS removeOneById(Integer id) {
        boolean b = this.removeById(id);
        if (!b){
            return RS.error();
        }
        return RS.ok();
    }

    @Override
    public RS removeByIdsE(List<Integer> ids) {
        boolean b = this.removeByIds(ids);
        if (!b){
            return RS.error();
        }
        return RS.ok();
    }

    @Override
    public RS<List<ShopDto>> recommend(@RequestParam("uid") String uid) throws IOException {



        List<Integer> o = (List<Integer>) redisTemplate.boundValueOps("SIMILAR_" + uid).get();

        if (o==null||"default".equals(uid)){
            ShopDto shopDto = new ShopDto();
            shopDto.setName("请先浏览商品，产生用户行为");
            shopDto.setTags("请先浏览商品，产生用户行为");
            shopDto.setHot("请先浏览商品，产生用户行为");
            shopDto.setLogo("http://img.mabach.cn/lewa.jpg");
            shopDto.setPricePerMan(0);
            return RS.ok(Arrays.asList(shopDto));
        }



        List<ShopEntity> shopEntities = (List<ShopEntity>) this.listByIds(o);



        return RS.ok(shopEntities);
    }
//封装从ES中根据sid查询的方法
    private ShopDto searchFormEs( Integer sid) throws IOException {
        Request request = new Request("GET", "/shop/_search");
        JSONObject json = new JSONObject();
        json.put("_source","*");
        json.put("query",new JSONObject());
        json.getJSONObject("query").put("match",new JSONObject());
        json.getJSONObject("query").getJSONObject("match").put("_id",sid);


//        开始查询
        request.setJsonEntity(json.toJSONString());
        Response response = restHighLevelClient.getLowLevelClient().performRequest(request);
        String s = EntityUtils.toString(response.getEntity());
//        获取查询结果
        JSONObject jsonObject = JSONObject.parseObject(s);
        JSONArray jsonArray = jsonObject.getJSONObject("hits").getJSONArray("hits");
        JSONObject o = jsonArray.getJSONObject(0);
        ShopDto shopDto = new ShopDto();
        shopDto.setId(sid);

        String category = o.getJSONObject("_source").getString("category");
        shopDto.setCategory(category);
        String hot = o.getJSONObject("_source").getString("hot");
        shopDto.setHot(hot);
        String name = o.getJSONObject("_source").getString("name");
        shopDto.setName(name);
        String logo = o.getJSONObject("_source").getString("logo");
        shopDto.setLogo(logo);
        String tags = o.getJSONObject("_source").getString("tags");
        shopDto.setTags(tags);
        Integer price = Integer.valueOf(o.getJSONObject("_source").get("price_per_man").toString());
        shopDto.setPricePerMan(price);
        BigDecimal score = new BigDecimal(o.getJSONObject("_source").get("remark_score").toString());
        shopDto.setRemarkScore(score);


        return shopDto;


    }

    @Override
    public Map<String,Object> search(@RequestParam(value = "longitude",required = false) BigDecimal longitude,
                                     @RequestParam(value = "latitude",required = false) BigDecimal latitude,
                                     @RequestParam("keyword") String keyword,
                                     @RequestParam(value = "orderby",required = false)String orderby,
                                     @RequestParam(value = "categoryId",required = false)Integer categoryId,
                                     @RequestParam(value = "tags",required = false)String tags) throws IOException {


        Request request = new Request("GET", "/shop/_search");

        JSONObject json = new JSONObject();
        json.put("_source","*");

//        分页
        json.put("from",0);
        json.put("size",50);
//        构建script_fields
        json.put("script_fields",new JSONObject());
        json.getJSONObject("script_fields").put("distance",new JSONObject());
        json.getJSONObject("script_fields").getJSONObject("distance").put("script",new JSONObject());
        json.getJSONObject("script_fields").getJSONObject("distance").getJSONObject("script").put("source","haversin(lat,lon, doc['location'].lat, doc['location'].lon)");
        json.getJSONObject("script_fields").getJSONObject("distance").getJSONObject("script").put("lang","expression");
        json.getJSONObject("script_fields").getJSONObject("distance").getJSONObject("script").put("params",new JSONObject());
        json.getJSONObject("script_fields").getJSONObject("distance").getJSONObject("script").getJSONObject("params").put("lat",latitude);
        json.getJSONObject("script_fields").getJSONObject("distance").getJSONObject("script").getJSONObject("params").put("lon",longitude);
//        构建query
//        Map<String, Object> analyzeKeyword = analyzeKeyword(keyword);
        Map<String, Object> analyzeKeyword = new HashMap<>();
        Boolean isAffectFilter=true; //影响召回
        Boolean isAffectOrder=true; //影响排序

        json.put("query",new JSONObject());

        json.getJSONObject("query").put("function_score",new JSONObject());
        //            构建must
        json.getJSONObject("query").getJSONObject("function_score").put("query",new JSONObject());
        json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").put("bool",new JSONObject());
        json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").put("must",new JSONArray());
        json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                getJSONArray("must").add(new JSONObject());
        json.put("highlight",new JSONObject());

//        高亮
        json.getJSONObject("highlight").put("fields",new JSONObject());
        json.getJSONObject("highlight").getJSONObject("fields").put("name",new JSONObject());
        json.getJSONObject("highlight").getJSONObject("fields").put("hot",new JSONObject());

        int index=0;
        int should=0;

        //        判断关键词是否相关性，如果没有相关性则执行默认搜索
        if(analyzeKeyword.keySet().size()==0&&isAffectFilter){

//            构建bool

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).put("bool",new JSONObject());
//            构建should
            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").put("should",new JSONArray());
//            构建name的match
            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").add(new JSONObject());

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").getJSONObject(should)
            .put("match",new JSONObject());

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should")
                    .getJSONObject(should).getJSONObject("match").put("name",new JSONObject());

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should")
                    .getJSONObject(should).getJSONObject("match").getJSONObject("name").put("query",keyword);

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should")
                    .getJSONObject(should).getJSONObject("match").getJSONObject("name").put("boost",BOOST);


//构建第二个match category_name

            should++;
            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").add(new JSONObject());

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").getJSONObject(should)
                    .put("match",new JSONObject());


            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should")
                    .getJSONObject(should).getJSONObject("match").put("category_name",new JSONObject());

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should")
                    .getJSONObject(should).getJSONObject("match").getJSONObject("category_name").put("query",keyword);

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should")
                    .getJSONObject(should).getJSONObject("match").getJSONObject("category_name").put("boost",0);

            //构建第三个match
            should++;


            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").add(new JSONObject());
//            构建hot的match
            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").getJSONObject(should)
                    .put("match",new JSONObject());


            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").getJSONObject(should)
                    .put("match",new JSONObject());

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should")
                    .getJSONObject(should).getJSONObject("match").put("hot",new JSONObject());

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should")
                    .getJSONObject(should).getJSONObject("match").getJSONObject("hot").put("query",keyword);

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
                    .getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should")
                    .getJSONObject(should).getJSONObject("match").getJSONObject("hot").put("boost",BOOST);





//如果有相关性，则重新构造match为bool
        }else {
            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                    getJSONArray("must").getJSONObject(index).put("bool",new JSONObject());
            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                    getJSONArray("must").getJSONObject(index).getJSONObject("bool").put("should",new JSONArray());

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                    getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").add(new JSONObject());
            int shouldIndex=0;
           json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                    getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").
                    getJSONObject(shouldIndex).put("match",new JSONObject());

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                    getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").
                    getJSONObject(shouldIndex).getJSONObject("match").put("name",new JSONObject());

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                    getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").
                    getJSONObject(shouldIndex).getJSONObject("match").getJSONObject("name").put("query",keyword);

            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                    getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").
                    getJSONObject(shouldIndex).getJSONObject("match").getJSONObject("name").put("boost",BOOST);
//遍历相关性的token,增加到term中
            for (String s : analyzeKeyword.keySet()) {
                Integer id = (Integer) analyzeKeyword.get(s);
                shouldIndex++;

                json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                        getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").
                        add(new JSONObject());
                json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                        getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").
                        getJSONObject(shouldIndex).put("term",new JSONObject());

                json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                        getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").
                        getJSONObject(shouldIndex).getJSONObject("term").put("category_id",new JSONObject());

                json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                        getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").
                        getJSONObject(shouldIndex).getJSONObject("term").getJSONObject("category_id").put("value",id);

                json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                        getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("should").
                        getJSONObject(shouldIndex).getJSONObject("term").getJSONObject("category_id").put("boost",0);
            }


        }
//构建第二个bool
        index++;
        json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                getJSONArray("must").add(new JSONObject());

//        term过滤未禁用商家
        json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
        getJSONArray("must").getJSONObject(index).put("bool",new JSONObject());

        json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                getJSONArray("must").getJSONObject(index).getJSONObject("bool").put("must",new JSONArray());

        json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("must")
                .add(new JSONObject());

        json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("must")
                .getJSONObject(0).put("term",new JSONObject());

        json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                getJSONArray("must").getJSONObject(index).getJSONObject("bool").getJSONArray("must")
                .getJSONObject(0).getJSONObject("term").put("seller_disabled_flag",0);






//        term过滤类目
        if (categoryId!=null){
            index++;
            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                    getJSONArray("must").add(new JSONObject());
            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                    getJSONArray("must").getJSONObject(index).put("term",new JSONObject());
            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                    getJSONArray("must").getJSONObject(index).getJSONObject("term").put("category_id",categoryId);
        }
//        term过滤标签
        if (!StringUtils.isEmpty(tags)){
            index++;
            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                    getJSONArray("must").add(new JSONObject());
            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                    getJSONArray("must").getJSONObject(index).put("term",new JSONObject());
            json.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").
                    getJSONArray("must").getJSONObject(index).getJSONObject("term").put("tags",tags);
        }

//        构建function
        json.getJSONObject("query").getJSONObject("function_score").put("functions",new JSONArray());
        json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").add(new JSONObject());

        int functionIndex=0;

        //      构建高斯评分
        json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                put("gauss", new JSONObject());
        json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                getJSONObject("gauss").put("location", new JSONObject());
        json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                getJSONObject("gauss").getJSONObject("location").put("origin", latitude.toString() + "," + longitude.toString());
        json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                getJSONObject("gauss").getJSONObject("location").put("scale", "200km");
        json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                getJSONObject("gauss").getJSONObject("location").put("offset", "0.1km");
        json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                getJSONObject("gauss").getJSONObject("location").put("decay", 0.5);
//        高斯距离权重
        json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                put("weight", DISTANCE_WEIGHT);

//         如果 orderby为空，则使用默认排序规则
        if (StringUtils.isEmpty(orderby)) {

// remark_score评分
            //第二组
            functionIndex++;
            json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").add(new JSONObject());
            json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                    put("field_value_factor", new JSONObject());
            json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                    getJSONObject("field_value_factor").put("field", "remark_score");
//        remark_score权重
            json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                    put("weight", REMARK_SCORE_WEIGHT);

            // seller_remark_score评分
//            第三组
            functionIndex++;
            json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").add(new JSONObject());
            json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex)
                    .put("field_value_factor", new JSONObject());
            json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                    getJSONObject("field_value_factor").put("field", "seller_remark_score");
//        seller_remark_score权重
            json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                    put("weight", SELLER_REMARK_SCORE_WEIGHT);

//如果相关性有值并且开启影响排序开关，构建相关性的评分权重
            if (analyzeKeyword.keySet().size()>0&&isAffectOrder){
                for (String s : analyzeKeyword.keySet()) {
                    Integer id = (Integer) analyzeKeyword.get(s);
                    functionIndex++;
                    json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").add(new JSONObject());
                    json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex)
                            .put("filter", new JSONObject());
                    json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                            getJSONObject("filter").put("term", new JSONObject());
                    json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                            getJSONObject("filter").getJSONObject("term").put("category_id",id);
//        category_id排序权重
                    json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                            put("weight", CATEGORY_ID_WEIGHT);
                }

            }

//构建score_mode
            json.getJSONObject("query").getJSONObject("function_score").put("score_mode", SCORE_MODE);
            //构建boost_mode
            json.getJSONObject("query").getJSONObject("function_score").put("boost_mode", BOOST_MODE);
        }else {
            functionIndex++;
//            如果传入价格排序，则按照价格来升序
            json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").add(new JSONObject());
            json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").
                    getJSONObject(functionIndex).put("field_value_factor",new JSONObject());
            json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").
                    getJSONObject(functionIndex).getJSONObject("field_value_factor").put("field","price_per_man");
            json.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).
                    put("weight", PRICE_WEIGHT);
            //构建score_mode
            json.getJSONObject("query").getJSONObject("function_score").put("score_mode", SCORE_MODE);
            //构建boost_mode
            json.getJSONObject("query").getJSONObject("function_score").put("boost_mode", BOOST_MODE);
        }


//        构建排序
        json.put("sort",new JSONArray());
        json.getJSONArray("sort").add(new JSONObject());
        json.getJSONArray("sort").getJSONObject(0).put("_score",new JSONObject());
        if (StringUtils.isEmpty(orderby)){
            json.getJSONArray("sort").getJSONObject(0).getJSONObject("_score").put("order","desc");
        }else {
//            价格升序
            json.getJSONArray("sort").getJSONObject(0).getJSONObject("_score").put("order","asc");
        }

//        聚合10个标签
        json.put("aggs",new JSONObject());
        json.getJSONObject("aggs").put("group_by_tags",new JSONObject());
        json.getJSONObject("aggs").getJSONObject("group_by_tags").put("terms",new JSONObject());
        json.getJSONObject("aggs").getJSONObject("group_by_tags").getJSONObject("terms").put("field","tags");
        json.getJSONObject("aggs").getJSONObject("group_by_tags").getJSONObject("terms").put("size",10);


        System.out.println(json.toString());
        request.setJsonEntity(json.toJSONString());
        Response response = restHighLevelClient.getLowLevelClient().performRequest(request);
        String s = EntityUtils.toString(response.getEntity());
//        获取查询结果
        JSONObject jsonObject = JSONObject.parseObject(s);
        JSONArray jsonArray = jsonObject.getJSONObject("hits").getJSONArray("hits");
//        结果实体结合
        ArrayList<ShopDto> list = new ArrayList<>();
//        查询结果中的category_id集合
        ArrayList<CategorySetEntity> category_List = new ArrayList<>();

        HashSet<String> categorySet = new HashSet<>();
        for (int i=0;i<jsonArray.size();i++) {
            JSONObject object = jsonArray.getJSONObject(i);
            Integer id = Integer.valueOf(object.get("_id").toString());
//            封装category id和name
            Integer category_id = Integer.valueOf(object.getJSONObject("_source").get("category_id").toString());
            String category_name = object.getJSONObject("_source").getString("category_name");
            categorySet.add(category_id+"-"+category_name);


//            获取距离
            BigDecimal distance = new BigDecimal(object.getJSONObject("fields").getJSONArray("distance").get(0).toString());
//            ShopEntity byIdE = getByIdE(id);
//            ShopDto shopDto = BeanUtilsMabach.doToDto(byIdE, ShopDto.class);
//            封装查询结果，内容全部从es中获取
            ShopDto shopDto = new ShopDto();
            shopDto.setId(id);
//            封装名称
            String name1 = object.getJSONObject("_source").getString("name");
//            封装hot
            String hot1 = object.getJSONObject("_source").getString("hot");
            shopDto.setName(name1);
            shopDto.setHot(hot1);
//            封装评分
            BigDecimal remark_score = new BigDecimal(object.getJSONObject("_source").get("remark_score").toString());
            shopDto.setRemarkScore(remark_score);
//            封装价格
            Integer price_per_man = Integer.valueOf(object.getJSONObject("_source").getString("price_per_man"));
            shopDto.setPricePerMan(price_per_man);
//            封装图片
            String logo = object.getJSONObject("_source").getString("logo");
            shopDto.setLogo(logo);


            shopDto.setDistance(distance.multiply(new BigDecimal(1000).setScale(0,BigDecimal.ROUND_CEILING)).intValue());
//           获取高亮
            JSONObject highlight = object.getJSONObject("highlight");
            JSONArray name=null;
            JSONArray hot=null;
            if (highlight!=null){
                name= highlight.getJSONArray("name");
                hot = highlight.getJSONArray("hot");
            }
//            高亮不为空则重新封装高亮
            if (name!=null){
                String s1 = name.get(0).toString().replace("<em>", "<em style=\"color: red\">");
                shopDto.setName(s1);

            }
//            高亮不为空则重新封装高亮
            if (hot!=null){
                String s2 = hot.get(0).toString().replace("<em>", "<em style=\"color: red\">");
                shopDto.setHot(s2);

            }

            list.add(shopDto);
        }
//循环set得到 id-name集合
        for (String s1 : categorySet) {
            String[] split = s1.split("-");
            CategorySetEntity setEntity = new CategorySetEntity();
            setEntity.setId(Integer.valueOf(split[0]));
            setEntity.setName(split[1]);
            category_List.add(setEntity);

        }


        HashMap<String, Object> hashMap = new HashMap<>();

//        获取标签
        JSONArray array = jsonObject.getJSONObject("aggregations").getJSONObject("group_by_tags").getJSONArray("buckets");
        ArrayList<Map> mapArrayList = new ArrayList<>();
        for (int i=0;i<array.size();i++){
            JSONObject object = array.getJSONObject(i);
            HashMap<String, Object> map = new HashMap<>();
            map.put("tags",object.getString("key"));
            map.put("num",object.getIntValue("doc_count"));
            mapArrayList.add(map);
        }

        hashMap.put("tags",mapArrayList);
        hashMap.put("category",category_List);
        hashMap.put("rs",RS.ok(list));


        return hashMap;
    }
//    借助Elasticsearch对传进来的关键词进行分词,并将分此后的token-id 封装到map里
    private Map<String,Object> analyzeKeyword(String keyword) throws IOException {
        HashMap<String, Object> map = new HashMap<>();
        Request request = new Request("GET", "/shop/_analyze");
        request.setJsonEntity("{\"field\": \"name\",\"text\" : \""+keyword+"\"}");
        Response response = restHighLevelClient.getLowLevelClient().performRequest(request);
        String s = EntityUtils.toString(response.getEntity());
        JSONObject jsonObject = JSONObject.parseObject(s);
        JSONArray jsonArray = jsonObject.getJSONArray("tokens");
        for(int i=0;i<jsonArray.size();i++){
            String token = jsonArray.getJSONObject(i).getString("token");
            Integer id = getCategoryIdByKeyword(token);
            if (id!=null){
                map.put(token,id);
            }

        }
        return map;
    }
//根据关键词获取categoryID （id和name需要自己维护）
    private Integer getCategoryIdByKeyword(String keyword){
        for (ListProperties listProperties : categoryProperties.getList()) {
            if(listProperties.getNames().contains(keyword)){
                return listProperties.getId();
            }
        }
        return null;



    }

//    @Test
//    public void test() throws IOException, InvalidArgumentException, com.sensorsdata.analytics.javasdk.exceptions.InvalidArgumentException {
//
//
//        final SensorsAnalytics sa = new SensorsAnalytics(new SensorsAnalytics.ConcurrentLoggingConsumer("F:\\logs\\access.log"));
//        HashMap<String, Object> properties = new HashMap<>();
//        String distinctId = "ABCDEF123456789";
//        properties.put("name","张三");
//        sa.track(distinctId,true,"ViewProduct",properties);
//        sa.shutdown();
//    }



}